package org.zk.dubbo_consumer.config;


import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.zk.dubbo_consumer.secutity.KickoutSessionControlFilter;
import org.zk.dubbo_consumer.secutity.MyShiroRealm;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 创建ShiroConfig配置
 */

@Configuration
public class ShiroConfig {
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
        /**
         * 测试是否进入Shiro配置，可删除
         */
        logger.info("---------------- 已经进入Shiro配置 ----------------------");

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //必须设置SecurityManager，Shiro的核心接口
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //没有登录的用户只能访问登录页面,就是进入登录页面的控制器
        shiroFilterFactoryBean.setLoginUrl("/user/toIndex");
//        //登陆成功后要跳转的链接
//        shiroFilterFactoryBean.setSuccessUrl("/auth/index");

        //自定义拦截器
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        //限制同一账号同时在线的个数
        filterMap.put("kickout", kickoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(filterMap);
        //权限控制map,在map中存入所有不用被shiro拦截的静态资源
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

//        filterChainDefinitionMap.put("/static/**", "anon");
//        filterChainDefinitionMap.put("/user/*", "anon");
//        filterChainDefinitionMap.put("/adminBill/*", "anon");
//        filterChainDefinitionMap.put("/admin/*", "anon");
//        filterChainDefinitionMap.put("/apply/*", "anon");
//        filterChainDefinitionMap.put("/applyRefund/*", "anon");
//        filterChainDefinitionMap.put("/broadcast/*", "anon");
//        filterChainDefinitionMap.put("/cart/*", "anon");
//        filterChainDefinitionMap.put("/catalog/*", "anon");
//        filterChainDefinitionMap.put("/comment/*", "anon");
//        filterChainDefinitionMap.put("/course/*", "anon");
//        filterChainDefinitionMap.put("/couUser/*", "anon");
//        filterChainDefinitionMap.put("/danmu/*", "anon");
//        filterChainDefinitionMap.put("/evaluate/*", "anon");
//        filterChainDefinitionMap.put("/inform/*", "anon");
//        filterChainDefinitionMap.put("/lessionBroadcast/*", "anon");
//        filterChainDefinitionMap.put("/lession/*", "anon");
//        filterChainDefinitionMap.put("/like/*", "anon");
//        filterChainDefinitionMap.put("/member/*", "anon");
//        filterChainDefinitionMap.put("/message/*", "anon");
//        filterChainDefinitionMap.put("/order/*", "anon");
//        filterChainDefinitionMap.put("/redund/*", "anon");
//        filterChainDefinitionMap.put("/study/*", "anon");
//        filterChainDefinitionMap.put("/subject/*", "anon");
//        filterChainDefinitionMap.put("/type/*", "anon");
//        filterChainDefinitionMap.put("/teacherPhoneLoginDes", "anon");
//        filterChainDefinitionMap.put("/teacherIndex2", "anon");
//        filterChainDefinitionMap.put("/getShowTeacher", "anon");
//        filterChainDefinitionMap.put("/toCourseMsg", "anon");
//        filterChainDefinitionMap.put("/toInfo","anon");

//        filterChainDefinitionMap.put("/auth/login","anon");
        //logout是shiro提供的过滤器
//        filterChainDefinitionMap.put("/auth/logout","logout");
        //被踢出后
        filterChainDefinitionMap.put("/user/kickout","anon");
//        filterChainDefinitionMap.put("/**","authc,kickout");
        filterChainDefinitionMap.put("/*","anon");
//        filterChainDefinitionMap.put("/user/kickout","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    @Bean
    public SecurityManager securityManager() {
        /**
         * 判断是否进入身份认证操作的配置——————————————
         */
        logger.info("---------------- 已进入身份认证的总操作部分 ----------------------");

        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm
        securityManager.setRealm(myShiroRealm());
        //自定义缓存实现，使用redis
        securityManager.setCacheManager(cacheManager());
        //自定义session管理，使用redis
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 身份认证realm：(这个需要自己写，账号密码效验；权限等)
     *
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
        MyShiroRealm myShiroRealm = new MyShiroRealm();
        return myShiroRealm;
    }


    // 配置org.apache.shiro.web.session.mgt.DefaultWebSessionManager(shiro session的管理)
    @Bean
    public DefaultWebSessionManager getDefaultWebSessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setGlobalSessionTimeout(1000 * 60 * 60 * 60);// 会话过期时间，单位：毫秒(在无操作时开始计时)--->一分钟,用于测试
        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
        defaultWebSessionManager.setSessionIdCookieEnabled(true);
        return defaultWebSessionManager;
    }

    /**
     * cacheManager缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * 配置shiro  redisManager
     * 使用的是shiro-redis插件
     *
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);//配置端口
        redisManager.setExpire(1800);//配置缓存过期时间
        redisManager.setTimeout(0);//配置连接超时时间
        //redisManager.setPassword(password);//配置连接密码
        return redisManager;
    }

    /**
     * Session Manager
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * RedisSessionDao shiro sessionDao层的实现  通过redis
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }


    /**
     * 限制同一账号登录同时登录人数控制
     *
     * @return
     */
    @Bean
    public KickoutSessionControlFilter kickoutSessionControlFilter() {
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        kickoutSessionControlFilter.setCache(cacheManager());
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        kickoutSessionControlFilter.setKickoutAfter(false);//踢出之前登录的/之后登录的用户，默认提出之前登录的用户
        kickoutSessionControlFilter.setMaxSession(1);//同一账号最大回话数，默认1
        kickoutSessionControlFilter.setKickoutUrl("/auth/kickout");//踢出后到的地址
        return kickoutSessionControlFilter;
    }

    /**
     * 授权所有配置
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 使授权注解起作用不如不想配置可以在pom文件中加入
     * <dependency>
     * <groupId>org.springframework.boot</groupId>
     * <artifactId>spring-boot-starter-aop</artifactId>
     * <version>2.0.4.RELEASE</version>
     * </dependency>
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * Shiro生命周期处理器
     */
    @Bean
    public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

}
